﻿using System;
using System.Collections.Generic;
using Utilities.GlobalData;
using Utilities.XmlReader;

namespace AlgoImpl.Constraints
{
    public class ConstraintsChecker
    {
        private string m_WorkerId;
        private string m_ShiftId;
        private Constraints m_Constraints = new Constraints();

        private static volatile ConstraintsChecker s_Instance = null;
        private static object s_LockObj = new Object();

        public static ConstraintsChecker Instance
        {
            get
            {
                if (s_Instance == null)
                {
                    lock (s_LockObj)
                    {
                        if (s_Instance == null)
                        {
                            s_Instance = new ConstraintsChecker();
                        }

                    }
                }

                return s_Instance;
            }
        }

        public Constraints Constraints { get { return m_Constraints; } }

        private ConstraintsChecker() { }

        public void InitializeWorkerAndShift(string workerId, string shiftId)
        {
            m_WorkerId = workerId;
            m_ShiftId = shiftId;
        }

        public bool CheckAllConstraints(ShiftRequests sr)
        {
            foreach (KeyValuePair<eConstraints, SingleConstraint> kvp in m_Constraints.Constrains)
            {
                switch (kvp.Key)
                {
                    case eConstraints.FULLSHIFT:
                        if(kvp.Value.IsTrue)
                        {
                            if (SharedData.Instance.GetShiftById(m_ShiftId).IsFull())
                            {
                                return false;
                            }
                        }
                        break;
                    case eConstraints.MAXSHIFTSOFWORKER:
                        if (kvp.Value.IsTrue)
                        {
                            if (!SharedData.Instance.GetWorkerById(m_WorkerId).CanGiveMoreShifts())
                            {
                                return false;
                            }
                        }
                        break;
                    case eConstraints.MINNUMOFSHIFTSFORWORKER:
                        if (kvp.Value.IsTrue) 
                        {
                            
                        }
                        break;
                    case eConstraints.PERIODBETWEENSHIFTS:
                        if (kvp.Value.IsTrue)
                        {
                            if (!timeBetweenShiftsAreOk())
                            {
                                return false;
                            }
                        }
                        break;
                    case eConstraints.SHIFTFORBIDENFORWORKER:
                        if (kvp.Value.IsTrue)
                        {
                            if (sr != null && sr.IsShiftForbidenForWorker(m_WorkerId, m_ShiftId))
                            {
                                return false;
                            }
                        }
                        break;
                };
            }
            return true;
        }

        private bool timeBetweenShiftsAreOk()
        {
            bool isPosible = true;
            foreach (string registerdShift in SharedData.Instance.GetWorkerById(m_WorkerId).GetAllShiftsIds())
            {
                if ((Math.Abs(int.Parse(registerdShift) - (int.Parse(m_ShiftId))) <= m_Constraints.Constrains[eConstraints.PERIODBETWEENSHIFTS].Value))
                {
                    isPosible = false;
                    break;
                }
            }
            return isPosible;
        }      
    }


    public class Constraints
    {
        private Dictionary<eConstraints, SingleConstraint> m_Constrains;

        public Constraints()
        {
            m_Constrains = new Dictionary<eConstraints, SingleConstraint>();
        }

        public Dictionary<eConstraints, SingleConstraint> Constrains { get { return m_Constrains; } }


        public void InitAsTrue()
        {
            m_Constrains.Clear();
            m_Constrains.Add(eConstraints.FULLSHIFT, new SingleConstraint(true, SingleConstraint.k_SingForNonValue));
            m_Constrains.Add(eConstraints.MAXSHIFTSOFWORKER, new SingleConstraint(true, SingleConstraint.k_SingForNonValue));
            m_Constrains.Add(eConstraints.SHIFTFORBIDENFORWORKER, new SingleConstraint(true, SingleConstraint.k_SingForNonValue));
            m_Constrains.Add(eConstraints.PERIODBETWEENSHIFTS,
                new SingleConstraint(true, int.Parse(MyXmlReader.GetValueOfSingleConstraint(
                    eConstraints.PERIODBETWEENSHIFTS))));
            m_Constrains.Add(eConstraints.MINNUMOFSHIFTSFORWORKER,
                new SingleConstraint(true, int.Parse(MyXmlReader.GetValueOfSingleConstraint(
                    eConstraints.MINNUMOFSHIFTSFORWORKER))));

        }

        public void ChangeSingleConstraint(eConstraints con, bool trueOrFalse, int val)
        {
            m_Constrains[con].IsTrue = trueOrFalse;
            m_Constrains[con].Value = val;
        }

        // TO DO
        public static void initializeConstraintsFromFile()
        {

        }
    }

    public class SingleConstraint
    {
        public const int k_SingForNonValue = -1;
        private bool m_IsTrue = true;
        private int m_Value;

        public SingleConstraint(bool trueOrFalse, int value)
        {
            m_IsTrue = trueOrFalse;
            m_Value = value;
        }

        public bool IsTrue
        {
            get { return m_IsTrue; }
            set { m_IsTrue = value; }
        }
        public int Value
        {
            get { return m_Value; }
            set { m_Value = value; }
        }
    }
}
